﻿using System;
using System.Collections.Generic;
using System.Linq;
using CI.Interfaces;
using CI.Mesopotamia;
using CI.Mesopotamia.Dal;
using CI.Mesopotamia.WebService;
using CI.Organism;
using CI.Utils;

namespace CI.DAL
{
    /// <summary>
    /// Grid Webservice DAL
    /// </summary>
    public class GridWSDAL : IDAL
    {
        // webservice
        private InboundClient _wsClient;
        // retry count
        private const int MAX_RETRY_COUNT = 3;
        // retry sleep, 10 seconds
        private const int RETRY_SLEEP = 10000;

        private readonly SimEnv _simEnv = SimEnv.Instance;

        /// <summary>
        /// Load into the hosting environment from the Grid
        /// </summary>
        /// <param name="environment">dal environment name to load</param>
        /// <param name="hostEnvironment">host environment</param>
        /// <param name="maxLoadCount">max number of organism to load from the grid</param>
        /// <param name="selectedOrganismsToLoad"></param>
        /// <returns>true if successfull</returns>
        public IHostingEnvironment LoadHostingEnvironment(string environment, IHostingEnvironment hostEnvironment, int maxLoadCount, List<Guid> selectedOrganismsToLoad)
        {
            #region Argument Checks
            if (string.IsNullOrEmpty(environment))
                throw new ArgumentException("environment");
            if (hostEnvironment == null)
                throw new ArgumentException("hostEnvironment");
            #endregion

            _simEnv.TraceLogger.LogDebug("Grid LoadHostingEnvironment - Start");

            // retry count
            int retryCount = 0;
            // did we get a successfull connection
            bool connectionSuccessful = false;

            do
            {
                // open a connection
                _wsClient = new InboundClient();
#if (DEBUG&&GRIDLOCAL)
                // if debug use the local endpoint for debugging
                _wsClient.Endpoint.Address = new System.ServiceModel.EndpointAddress("http://localhost/MesopotamiaDCProxy/inbound.svc");
#endif
                retryCount++;

                try
                {
                    _simEnv.TraceLogger.LogDebug("Please wait, communicating  with grid");
                    // update status, but if paused dont overwrite the previous stat
                    if (!SimEnv.Instance.PauseState)
                        hostEnvironment.ProcessingState = "Communicating with grid";

                    // load it in
                    DALList dalList = _wsClient.LoadDal(environment, Mesopotamia.Properties.Settings.Default.UserID, maxLoadCount, selectedOrganismsToLoad.ToArray());

                    _simEnv.TraceLogger.LogDebug(string.Format("Loaded {0} organisms", dalList.Count));

                    // copy them into the hosting environment
                    foreach (IOrganism organism in dalList)
                    {
                        organism.Energy = organism.InitEnergy;
                        organism.CIET = organism.InitCIET;
                        organism.Organisms = hostEnvironment.Organisms;
                        organism.HostingEnvironment = hostEnvironment;
                        hostEnvironment.Organisms.AliveAdd(organism);
                    }

                    // clear the dead list and inactive
                    hostEnvironment.Organisms.Dead.Clear();
                    hostEnvironment.Organisms.Inactive.Clear();
                    // got a successfull conection
                    connectionSuccessful = true;
                }
                catch (Exception ex)
                {
                    _simEnv.TraceLogger.LogDebug("Exception loading organisms from GRID" + Environment.NewLine + ex.Message);
                    StatsLogger.Sleeper(RETRY_SLEEP);
                }
                finally
                {
                    // close it
                    _wsClient.Close();
                }
            } while ((connectionSuccessful == false) && (retryCount < MAX_RETRY_COUNT));

            // if unsuccesful fall back to xml
            if ((connectionSuccessful == false) && (retryCount >= MAX_RETRY_COUNT))
            {

                _simEnv.TraceLogger.LogDebug("Grid LoadHostingEnvironment - Failed");
                _simEnv.TraceLogger.LogDebug("Trying XML DAL - Start");

                var xmlDal = new XMLDAL();
                var resultHostEnvironment = xmlDal.LoadHostingEnvironment(environment, hostEnvironment, 0, selectedOrganismsToLoad);

                _simEnv.TraceLogger.LogDebug("Trying XML DAL - Finish : " + hostEnvironment);

                // if xml dal failed
                if (resultHostEnvironment == null)
                {
                    var testDal = new TestDAL();
                    resultHostEnvironment = testDal.LoadHostingEnvironment(environment, hostEnvironment, 0, selectedOrganismsToLoad);
                }

                // save result
                hostEnvironment = resultHostEnvironment;
            }

            _simEnv.TraceLogger.LogDebug("Grid LoadHostingEnvironment - Finish");

            return hostEnvironment;
        }

        /// <summary>
        /// Save our organisms and environment to the Grid
        /// </summary>
        /// <param name="environment">dal environment name to save</param>
        /// <param name="hostEnvironment">host environment</param>
        /// <param name="maxSaveCount">max number of organisms to save to the grid</param>
        /// <returns>true if successfull</returns>
        public bool SaveHostingEnvironment(string environment, IHostingEnvironment hostEnvironment, int maxSaveCount)
        {
            #region Argument Checks
            if (string.IsNullOrEmpty(environment))
                throw new ArgumentException("environment");
            if (hostEnvironment == null)
                throw new ArgumentException("hostEnvironment");
            #endregion

            _simEnv.TraceLogger.LogDebug("Grid SaveHostingEnvironment - Start");

            int retryCount = 0;
            bool connectionSuccessful = false;

            do
            {
                // open a connection
                _wsClient = new InboundClient();
#if (DEBUG&&GRIDLOCAL)
                // if debug use the local endpoint for debugging
                _wsClient.Endpoint.Address = new System.ServiceModel.EndpointAddress("http://localhost/MesopotamiaDCProxy/inbound.svc");
#endif
                retryCount++;

                try
                {
                    DALList dalList = CreateUploadList(hostEnvironment);
                    _simEnv.TraceLogger.LogDebug(string.Format("{0} organisms in environment, trimming to {1}", dalList.Count, maxSaveCount));

                    // trim if we need to
                    if ((maxSaveCount > 0) && (dalList.Count > maxSaveCount))
                        dalList.RemoveRange(maxSaveCount - 1, dalList.Count - maxSaveCount);

                    _simEnv.TraceLogger.LogDebug(string.Format("Saving {0} organisms", dalList.Count));
                    _simEnv.TraceLogger.LogDebug("Please wait, communicating  with grid");
                    // update status
                    hostEnvironment.ProcessingState = "Communicating with grid";

                    // save them
                    var gridSavedCount = _wsClient.SaveDal(environment, dalList, Mesopotamia.Properties.Settings.Default.UserID);

                    _simEnv.TraceLogger.LogDebug(string.Format("Saved {0} of {1} organisms", gridSavedCount, dalList.Count));
                    connectionSuccessful = true;
                }
                catch (Exception ex)
                {
                    _simEnv.TraceLogger.LogDebug("Exception saving organisms to GRID : " + ex.Message);
                    StatsLogger.Sleeper(RETRY_SLEEP);
                }
                finally
                {
                    // close it
                    _wsClient.Close();
                }
            } while ((connectionSuccessful == false) && (retryCount < MAX_RETRY_COUNT));

            // if unsuccesful fall back to xml
            if ((connectionSuccessful == false) && (retryCount >= MAX_RETRY_COUNT))
            {
                _simEnv.TraceLogger.LogDebug("Grid SaveHostingEnvironment - Failed");
                _simEnv.TraceLogger.LogDebug("Trying XML DAL - Start");

                var xmlDal = new XMLDAL();
                connectionSuccessful = xmlDal.SaveHostingEnvironment(environment, hostEnvironment, 0);
                _simEnv.TraceLogger.LogDebug("Trying XML DAL - Finish : " + connectionSuccessful);
            }

            _simEnv.TraceLogger.LogDebug("Grid SaveHostingEnvironment - Finish");
            return connectionSuccessful;
        }

        /// <summary>
        /// Can we connect to the grid
        /// </summary>
        /// <returns></returns>
        public static bool GridOnline()
        {
            return ScenarioGrid.GridOnline();
        }


        /// <summary>
        /// Create a upload list for the DAL
        /// </summary>
        /// <param name="hostEnvironment"></param>
        /// <returns></returns>
        public static DALList CreateUploadList(IHostingEnvironment hostEnvironment)
        {
            // create dal list
            var dalList = new DALList();

            dalList.AddRange(DalFactory.CreateFittestList(hostEnvironment));

            return dalList;
        }

    }
}
